package com.songlanyun.modules.payorder.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.enums.*;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.kqUtils.InitOrder;
import com.songlanyun.common.kqUtils.QuickPayEnum;
import com.songlanyun.common.kqUtils.quick.Bill99ConfigInfo;
import com.songlanyun.common.kqUtils.quick.BuildHttpsClient;
import com.songlanyun.common.supplychainapi.order.ApiOrderCommon;
import com.songlanyun.common.supplychainapi.order.model.Address;
import com.songlanyun.common.supplychainapi.order.model.OrderParam;
import com.songlanyun.common.supplychainapi.order.model.Spu;
import com.songlanyun.common.utils.*;
import com.songlanyun.common.wxUtils.HttpClientUtil;
import com.songlanyun.modules.account.service.UserVerifiedService;
import com.songlanyun.modules.exception.OrderException;
import com.songlanyun.modules.goods.entity.Goods;
import com.songlanyun.modules.goods.service.GoodsService;
import com.songlanyun.modules.message.service.SendPrivateMessageMsgService;
import com.songlanyun.modules.order.entity.ChildOrder;
import com.songlanyun.modules.order.entity.Order;
import com.songlanyun.modules.order.entity.OrderReceipt;
import com.songlanyun.modules.order.model.dto.HouniaoCheckDTO;
import com.songlanyun.modules.order.model.dto.SubmitOrderUseCoupon;
import com.songlanyun.modules.order.model.vo.PayOrderDetailVo;
import com.songlanyun.modules.order.service.ChildOrderService;
import com.songlanyun.modules.order.service.HouniaoOrderService;
import com.songlanyun.modules.order.service.OrderOperationService;
import com.songlanyun.modules.order.service.OrderService;
import com.songlanyun.modules.payorder.dao.KqBankDao;
import com.songlanyun.modules.payorder.dao.PayOrderDao;
import com.songlanyun.modules.payorder.entity.KqBank;
import com.songlanyun.modules.payorder.entity.PayOrder;
import com.songlanyun.modules.payorder.model.dto.*;
import com.songlanyun.modules.payorder.service.PayOrderService;
import com.songlanyun.modules.rabbitmq.mq.producer.SendOrderOrRightsOrderMsgService;
import com.songlanyun.modules.refillorder.service.SaleRefillCardOrderService;
import com.songlanyun.modules.saleconfig.entity.SaleConfig;
import com.songlanyun.modules.saleconfig.service.SaleConfigService;
import com.songlanyun.pay.bean.AdaPayConfirmBean;
import com.songlanyun.pay.bean.PayBean;
import com.songlanyun.pay.common.api.ApiResult;
import com.songlanyun.pay.service.AdaKjPayService;
import com.songlanyun.pay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


@Service("payOrderService")
@Slf4j
public class PayOrderServiceImpl extends ServiceImpl<PayOrderDao, PayOrder> implements PayOrderService {

    // 报税直供商品标识
//    private static boolean ISTAXDIRECT = false;

    @Autowired
    private SaleConfigService saleConfigService;

    @Autowired
    private SaleRefillCardOrderService saleRefillCardOrderService;

    @Autowired
    private OrderOperationService orderOperationService;

    @Resource
    @Qualifier("payService2")
    private PayService payService;

    @Resource
    RedisUtils redisUtils;

    @Autowired
    private OrderService orderService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ApiOrderCommon apiOrderCommon;

    @Autowired
    private AdaKjPayService adaKjPayService;

    @Autowired
    private HouniaoApiUtil houniaoApiUtil;

    @Autowired
    private HouniaoOrderService houniaoOrderService;

    @Autowired
    private ChildOrderService childOrderService;

    @Autowired
    private UserVerifiedService userVerifiedService;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private BuildHttpsClient buildHttpsClient;

    @Autowired
    private KqBankDao kqBankDao;


    @Resource
    private SendOrderOrRightsOrderMsgService sendOrderOrRightsOrderMsgService;

    @Autowired
    private SendPrivateMessageMsgService sendPrivateMessageMsgService;

    @Override
    public PayOrder create(PayOrder entity) {
        this.baseMapper.insert(entity);
        return entity;
    }

    @Override
    public PayOrder modify(PayOrder entity) {
        this.baseMapper.updateById(entity);
        return entity;
    }


    @Override
    public void remove(Long id) {

    }

    private PayOrder buildPayOrder(Long userId, BigDecimal totalMoney, OrderConstant.PayMode payMode, OrderConstant.OrderType orderType, Long expiredTime) {
        PayOrder payOrder = new PayOrder();
        payOrder.setClose(false);
        payOrder.setUserId(userId);
        payOrder.setCloseMode(OrderConstant.CloseMode.NO);
        payOrder.setCode(OrderGen.generateOrderNo());
        payOrder.setCreateTimeMillis(System.currentTimeMillis());
        payOrder.setUserId(userId);
        payOrder.setExpiredPayTime(expiredTime);
        payOrder.setPaymentStatus(OrderConstant.PaymentStatus.NO_PAY);
        payOrder.setPayMode(payMode);
        payOrder.setPayTime(0L);
        payOrder.setThirdPayCode("");
        payOrder.setTotalAmount(totalMoney);
        payOrder.setOrderType(orderType);
        payOrder.setPointGoods(false);
        return payOrder;
    }

    private PayOrder buildPayOrder(Long userId, BigDecimal totalMoney, BigDecimal totalPoint, OrderConstant.PayMode payMode, OrderConstant.OrderType orderType, Long expiredTime) {
        PayOrder payOrder = new PayOrder();
        payOrder.setClose(false);
        payOrder.setUserId(userId);
        payOrder.setCloseMode(OrderConstant.CloseMode.NO);
        payOrder.setCode(OrderGen.generateOrderNo());
        payOrder.setCreateTimeMillis(System.currentTimeMillis());
        payOrder.setUserId(userId);
        payOrder.setExpiredPayTime(expiredTime);
        payOrder.setPaymentStatus(OrderConstant.PaymentStatus.NO_PAY);
        payOrder.setPayMode(payMode);
        payOrder.setPayTime(0L);
        payOrder.setThirdPayCode("");
        payOrder.setTotalAmount(totalMoney);
        payOrder.setTotalPoint(totalPoint);
        payOrder.setOrderType(orderType);
        payOrder.setPointGoods(true);
        return payOrder;
    }


    /**
     * 初始化支付订单
     *
     * @param userId
     * @param totalMoney
     * @return
     */
    @Override
    public PayOrder initPayOrder(Long userId, BigDecimal totalMoney, OrderConstant.PayMode payMode, OrderConstant.OrderType orderType) {
        SaleConfig config = saleConfigService.getConfig(true);
        long expiredTimestamp = config.getPaymentDelayConfig().getExpiredTimestamp(System.currentTimeMillis());
        PayOrder payOrder = buildPayOrder(userId, totalMoney, payMode, orderType, expiredTimestamp);
        payOrder.setGoodsImages(new ArrayList<>());
        payOrder.setTotalReduced(BigDecimal.ZERO);

        this.create(payOrder);
        return payOrder;
    }

    /**
     * @param userId
     * @param totalMoney
     * @param totalReduced
     * @param payMode
     * @param orderType
     * @param goodsImages
     * @param expiredPayTime
     * @return
     */
    @Override
    public PayOrder initPayOrderForSale(Long userId, BigDecimal totalMoney, BigDecimal totalReduced, OrderConstant.PayMode payMode, OrderConstant.OrderType orderType, List<String> goodsImages, Long expiredPayTime, SubmitOrderUseCoupon platformCoupon, GoodsConstant.AreaFeature areaFeature) {
        PayOrder payOrder = buildPayOrder(userId, totalMoney, payMode, orderType, expiredPayTime);
        payOrder.setGoodsImages(goodsImages);
        payOrder.setTotalReduced(totalReduced);
        payOrder.setAreaFeature(areaFeature);
        if (platformCoupon.getCouponId() > 0L) {
            payOrder.setCouponId(platformCoupon.getCouponId());
            payOrder.setCouponName(platformCoupon.getCouponName());
            payOrder.setCouponFaceValue(platformCoupon.getCouponFaceValue());
            payOrder.setCouponResultValue(platformCoupon.getCouponResultValue());
        }

        this.create(payOrder);
        return payOrder;
    }

    @Override
    public PayOrder initPayOrderForSaleAndPoint(Long userId, BigDecimal totalMoney, BigDecimal totalReduced, BigDecimal totalPoint, OrderConstant.PayMode payMode, OrderConstant.OrderType orderType, List<String> goodsImages, Long expiredPayTime, SubmitOrderUseCoupon platformCoupon, GoodsConstant.AreaFeature areaFeature) {
        PayOrder payOrder = buildPayOrder(userId, totalMoney, totalPoint, payMode, orderType, expiredPayTime);
        payOrder.setGoodsImages(goodsImages);
        payOrder.setTotalReduced(totalReduced);
        payOrder.setAreaFeature(areaFeature);
        if (platformCoupon.getCouponId() > 0L) {
            payOrder.setCouponId(platformCoupon.getCouponId());
            payOrder.setCouponName(platformCoupon.getCouponName());
            payOrder.setCouponFaceValue(platformCoupon.getCouponFaceValue());
            payOrder.setCouponResultValue(platformCoupon.getCouponResultValue());
        }
        this.create(payOrder);
        return payOrder;
    }


    /**
     * 成功支付后调用,所有安全校验必须之前处理完成才可以调用，来处理充值成功后的事情
     *
     * @param payOrderCode 订单号
     * @param thirdPayCode 第三方单号(退款)
     * @param returnMoney  金额
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public PayOrder paymentHandle(String payOrderCode, String thirdPayCode, BigDecimal returnMoney, OrderConstant.PayMode payMode) {
        System.out.println("进入修改订单状态");
        RLock lock = redissonClient.getLock(payOrderCode);
        lock.lock();
        PayOrder payOrder = null;
        try {
            payOrder = this.getByCode(payOrderCode, false);
            if (payOrder == null) {
                throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
            }

            if (OrderConstant.PaymentStatus.SUCCESS.equals(payOrder.getPaymentStatus())) {
                throw new RRException(OrderException.NOT_REPEAT_PAY);
            }

            //1 改变 payOrder 的相关状态，同时记录 thirdPayCode;
            payOrder.setThirdPayCode(thirdPayCode);
            payOrder.setPayTime(System.currentTimeMillis());
            payOrder.setPaymentStatus(OrderConstant.PaymentStatus.SUCCESS);
            if (payOrder.getTotalPoint().compareTo(BigDecimal.ZERO) > 0) {
                if (payMode.equals(OrderConstant.PayMode.ALIPAY)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY;
                }

                if (payMode.equals(OrderConstant.PayMode.WE_CHAT)) {
                    payMode = OrderConstant.PayMode.POINT_WE_CHAT;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HUIFU)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HUIFU;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HSQ)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HSQ;
                }
                if (payMode.equals(OrderConstant.PayMode.QUICK_PAY_BANK)) {
                    payMode = OrderConstant.PayMode.QUICK_PAY_BANK;
                }
            }

            payOrder.setPayMode(payMode);
            payOrder.setCloseMode(OrderConstant.CloseMode.NO);
            payOrder.setClose(false);
            payOrder.setCloseTime(0L);
            boolean b = this.updateById(payOrder);

            System.out.println("状态值==="+OrderConstant.PaymentStatus.SUCCESS);
            System.out.println("订单==="+payOrder);
            System.out.println("返回状态"+b);

            //充值订单
            if (payOrder.getOrderType().equals(OrderConstant.OrderType.REFILL_ORDER)) {
                saleRefillCardOrderService.paymentHandle(payOrder);
            } else {
                //消费订单 || 服务订单
                payOrder = orderOperationService.pay(payOrder);
//                try {
//                    uploadOrder(payOrder);
//                } catch (Exception ex) {
//                    log.info("上传订单给第三方失败：" + ex.getMessage());
//                }

            }
        }
        catch (Exception exception){
            log.error("支付订单成功回调异常 payOrdercode {} thirdPaycode {}", payOrderCode,thirdPayCode);
            log.error("支付异常信息"+ exception);
            System.out.println("支付订单异常打印"+exception);
        }
        finally {
            lock.unlock();
        }

        return payOrder;
    }


    /**
     * 支付宝成功支付后调用,所有安全校验必须之前处理完成才可以调用，来处理充值成功后的事情
     *
     * @param payOrderCode 订单号
     * @param thirdPayCode 第三方单号(退款)
     * @param receiptAmount  实收金额。商家在交易中实际收到的款项，单位为人民币（元），精确到小数点后 2 位
     * @param buyerPayAmount  用户在交易中支付的金额，单位为人民币（元），精确到小数点后 2 位
     * @return 更新后的支付订单实体
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public PayOrder paymentHandleForAliPay(String payOrderCode, String thirdPayCode, BigDecimal receiptAmount,
                                           BigDecimal buyerPayAmount,OrderConstant.PayMode payMode) {
        System.out.println("进入修改订单状态");
        RLock lock = redissonClient.getLock(payOrderCode);
        lock.lock();
        PayOrder payOrder = null;
        try {
            payOrder = this.getByCode(payOrderCode, false);
            if (payOrder == null) {
                throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
            }

            if (OrderConstant.PaymentStatus.SUCCESS.equals(payOrder.getPaymentStatus())) {
                throw new RRException(OrderException.NOT_REPEAT_PAY);
            }

            //1 改变 payOrder 的相关状态，同时记录 thirdPayCode;
            payOrder.setThirdPayCode(thirdPayCode);
            payOrder.setPayTime(System.currentTimeMillis());
            payOrder.setPaymentStatus(OrderConstant.PaymentStatus.SUCCESS);
            payOrder.setBuyerPayAmount(buyerPayAmount);
            payOrder.setReceiptAmount(receiptAmount);
            if (payOrder.getTotalPoint().compareTo(BigDecimal.ZERO) > 0) {
                if (payMode.equals(OrderConstant.PayMode.ALIPAY)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY;
                }

                if (payMode.equals(OrderConstant.PayMode.WE_CHAT)) {
                    payMode = OrderConstant.PayMode.POINT_WE_CHAT;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HUIFU)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HUIFU;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HSQ)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HSQ;
                }
            }

            payOrder.setPayMode(payMode);
            payOrder.setCloseMode(OrderConstant.CloseMode.NO);
            payOrder.setClose(false);
            payOrder.setCloseTime(0L);
            boolean b = this.updateById(payOrder);

            System.out.println("状态值==="+OrderConstant.PaymentStatus.SUCCESS);
            System.out.println("订单==="+payOrder);
            System.out.println("返回状态"+b);

            //充值订单
            if (payOrder.getOrderType().equals(OrderConstant.OrderType.REFILL_ORDER)) {
                saleRefillCardOrderService.paymentHandle(payOrder);
            } else {
                //消费订单 || 服务订单
                payOrder = orderOperationService.pay(payOrder);
//                try {
//                    uploadOrder(payOrder);
//                } catch (Exception ex) {
//                    log.info("上传订单给第三方失败：" + ex.getMessage());
//                }

            }
        }
        catch (Exception exception){
            log.error("支付订单成功回调异常 payOrdercode {} thirdPaycode {}", payOrderCode,thirdPayCode);
            log.error("支付异常信息"+ exception);
            System.out.println("支付订单异常打印"+exception);
        }
        finally {
            lock.unlock();
        }

        return payOrder;
    }

    @Override
    public void uploadOrder(PayOrder payOrder) {
        //第三方订单下单
        if (payOrder.getOrderType().equals(OrderConstant.OrderType.SALE_ORDER)
                && OrderConstant.PaymentStatus.SUCCESS.equals(payOrder.getPaymentStatus())) {
            List<Order> orders = payOrder.loadOrders();
            for (Order order : orders) {
                if (order.getThird() && !order.getMarketingType().equals(2)) {
                    uploadOrderEvent(order);
                }
            }
        }
    }

    @Override
    public void uploadOrderEvent(Order order) {
        boolean ISTAXDIRECT = false;
        OrderReceipt orderReceipt = order.loadOrderReceipt();
        Address address = Address.builder()
                .phone(orderReceipt.getMobile())
                .consignee(orderReceipt.getReceiver())
                .province(orderReceipt.getProvinceName())
                .city(orderReceipt.getCityName())
                .area(orderReceipt.getAreaName())
                .street(" ")
                .description(orderReceipt.getAddress())
                .build();
        List<ChildOrder> childOrderList = order.getChildOrderList(true);
        Spu[] spuArr = childOrderList.stream().map(o -> Spu.builder().sku(o.getThirdSkuId()).number(o.getNumber()).build()).toArray(Spu[]::new);
        OrderParam orderParam = OrderParam.builder()
                .address(address)
                .orderSn(order.getOrderCode())
                .spu(spuArr)
                .build();
//        apiOrderCommon.orderSubmit(orderParam);
        // 新版本只有候鸟订单渠道,当前策略为,直接下单

        List<HouniaoCheckDTO> list = new ArrayList<>();

        for (ChildOrder item : childOrderList) {
            HouniaoCheckDTO houniaoCheckDTO = new HouniaoCheckDTO();
            houniaoCheckDTO.setGoods_num(item.getNumber());
            houniaoCheckDTO.setSku_id(String.valueOf(item.getThirdSkuId()));
            houniaoCheckDTO.setGoods_spu(item.getThirdHouniaoSpuId());
            houniaoCheckDTO.setGoods_price(item.getRealPrice().toString());

            // 判断订单中是否有报税直供商品或者香港直邮商品
            Goods goods = goodsService.getOne(new QueryWrapper<Goods>().eq("spu_code", item.getThirdHouniaoSpuId()));
            if (goods.getTradeTypeId() == 1 || goods.getTradeTypeId() == 4){
                // 是直供保税产品
                ISTAXDIRECT = true;
            }

            list.add(houniaoCheckDTO);
        }

//        childOrderList.forEach( item -> {
//            HouniaoCheckDTO houniaoCheckDTO = new HouniaoCheckDTO();
//            houniaoCheckDTO.setGoods_num(item.getNumber());
//            houniaoCheckDTO.setSku_id(String.valueOf(item.getThirdSkuId()));
//            houniaoCheckDTO.setGoods_spu(item.getThirdHouniaoSpuId());
//            houniaoCheckDTO.setGoods_price(item.getRealPrice().toString());
//
//            // 判断订单中是否有报税直供商品或者香港直邮商品
//            Goods goods = goodsService.getOne(new QueryWrapper<Goods>().eq("spu_code", item.getThirdHouniaoSpuId()));
//            if (goods.getTradeTypeId() == 1 || goods.getTradeTypeId() == 4){
//                // 是直供保税产品
//                ISTAXDIRECT = true;
//            }
//
//            list.add(houniaoCheckDTO);
//        });
        JSONArray jsonArray = new JSONArray();

        list.forEach( item -> {
            JSONObject js = JSON.parseObject(JSONObject.toJSONString(item));
            js = houniaoApiUtil.sortJsonObject(js);
            jsonArray.add(js);
        });

        JSONObject buyNow = new JSONObject();
        buyNow.put("area_id", orderReceipt.getAreaCode()); //区/县地址id
        buyNow.put("user_address",orderReceipt.getAddress()); //详细地址
        buyNow.put("order_goods",jsonArray);

        buyNow.put("source_order_no", order.getOrderCode()); //来源订单单号
        buyNow.put("username", orderReceipt.getReceiver()); //收件人姓名
        buyNow.put("user_phone",Long.valueOf(orderReceipt.getMobile())); //收件人手机号


        // 判断是否为报税商品
        if (ISTAXDIRECT) {
            // 参数构建
            buyNow.put("id_card", order.getIdNo()); // 收件人 身份证号
            buyNow.put("is_pay",1);
            buyNow.put("customs_platform_code","21013609P6"); //电商平台海关备案代码，其中(1=保税直供)为必填，其他可选填
            buyNow.put("customs_platform_name","沈阳一链金服网络科技有限公司"); //电商平台海关备案名称，其中(1=保税直供)为必填，其他可选填
            buyNow.put("declarer", order.getRealName()); //订购人，其中(1=保税直供)为必填，其他可选填
            buyNow.put("declarer_id_card",order.getIdNo()); //订购人身份证，其中(1=保税直供)为必填，其他可选填
            buyNow.put("source_platform_no", order.getOrderCode()); //申报订单编号，其中(1=保税直供)为必填，其他可选填
            buyNow.put("amount_freight", String.valueOf(order.getRealFreight())); //运费金额，其中(1=保税直供)为必填，其他可选填
            buyNow.put("amount_discount", String.valueOf(order.getTotalReduced())); //优惠金额，其中(1=保税直供)为必填，其他可选填
            buyNow.put("amount_paid_in", String.valueOf(order.getTotalAmount())); //实付金额，其中(1=保税直供)为必填，其他可选填
            buyNow.put("pay_type",1); //1微信，2支付宝，其中(1=保税直供)为必填，其他可选填
            buyNow.put("pay_no", order.getOrderCode()); //支付交易号，其中(1=保税直供)为必填，其他可选填
            buyNow.put("create_time", Integer.parseInt(String.valueOf(order.getOrderTime() / 1000))); //订单创建时间，10位时间戳
            buyNow.put("pay_time", Integer.parseInt(String.valueOf(order.getPayTime() / 1000))); //订单支付时间，10位时间戳，其中(1=保税直供)为必填，其他可选填
            buyNow = houniaoApiUtil.sortJsonObject(buyNow);
        }

//        System.out.println("=============================================");
//        System.out.println(buyNow.toJSONString());
//        System.out.println("=============================================");

        JSONObject buyNowRes = houniaoApiUtil.client(buyNow, HouniaoConstant.ORDER_BUYNOW.getUrl());
        log.debug("商品下单" + buyNowRes.toJSONString());

        if (200 != buyNowRes.getInteger("code")) {
            log.error("候鸟商品下单失败==========================");
            log.error(buyNowRes.getString("msg"));
            throw new RRException(buyNowRes.getString("msg"));
        }
        // 订单支付完成后,更新三方订单号
        JSONObject buyNowData = buyNowRes.getJSONObject("data");

        JSONArray houniaoOrderRes = buyNowData.getJSONArray("order_items");

        childOrderList.forEach( item -> {
            houniaoOrderRes.forEach( item1 -> {
                JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(item1));
                if (item.getThirdHouniaoSpuId().equals(jsonObject.getJSONObject("order_goods").getString("goods_spu"))
                        && Objects.equals(item.getThirdSkuId(), jsonObject.getJSONObject("order_goods").getLong("sku_id"))) {

                    // 通过商品号与sku判断子订单
                    item.setThirdOrderNo(jsonObject.getString("order_no"));
                    childOrderService.updateById(item);

                }
            });
        });


    }

    @Override
    public PayOrder paymentFailHandle(String payOrderCode, String thirdPayCode, BigDecimal returnMoney, OrderConstant.PayMode payMode) {
        RLock lock = redissonClient.getLock(payOrderCode);
        lock.lock();
        PayOrder payOrder = null;
        try {
            payOrder = this.getByCode(payOrderCode, false);
            if (payOrder == null) {
                throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
            }

            if (OrderConstant.PaymentStatus.SUCCESS.equals(payOrder.getPaymentStatus())) {
                throw new RRException(OrderException.NOT_REPEAT_PAY);
            }

            //1 改变 payOrder 的相关状态，同时记录 thirdPayCode;
            payOrder.setThirdPayCode(thirdPayCode);
            payOrder.setPayTime(System.currentTimeMillis());
            payOrder.setPaymentStatus(OrderConstant.PaymentStatus.FAIL);
            if (payOrder.getTotalPoint().compareTo(BigDecimal.ZERO) > 0) {
                if (payMode.equals(OrderConstant.PayMode.ALIPAY)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY;
                }

                if (payMode.equals(OrderConstant.PayMode.WE_CHAT)) {
                    payMode = OrderConstant.PayMode.POINT_WE_CHAT;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HUIFU)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HUIFU;
                }

                if (payMode.equals(OrderConstant.PayMode.ALIPAY_HSQ)) {
                    payMode = OrderConstant.PayMode.POINT_ALIPAY_HSQ;
                }
            }

            payOrder.setPayMode(payMode);
            payOrder.setCloseMode(OrderConstant.CloseMode.THIRD_PAY_FAIL);
            payOrder.setClose(true);
            payOrder.setCloseTime(System.currentTimeMillis());
            this.updateById(payOrder);

//            //充值订单
//            if (payOrder.getOrderType().equals(OrderConstant.OrderType.REFILL_ORDER)) {
//                saleRefillCardOrderService.paymentHandle(payOrder);
//            } else {
//                //消费订单 || 服务订单
//                payOrder = orderOperationService.payFail(payOrder);
//            }

            if (!payOrder.getOrderType().equals(OrderConstant.OrderType.REFILL_ORDER)) {
                //消费订单 || 服务订单
                payOrder = orderOperationService.payFail(payOrder);
            }

        } finally {
            lock.unlock();
        }

        return payOrder;
    }


    @Override
    public PayOrder getByCode(String payOrderCode, Boolean tw) {
        PayOrder payOrder = this.getOne(new LambdaQueryWrapper<PayOrder>().eq(PayOrder::getCode, payOrderCode).last("limit 1"));
        if (payOrder == null) {
            if (tw) {
                throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
            }
        }
        return payOrder;
    }

    /**
     * 支付
     *
     * @param
     * @return
     */
    @Override
    public ApiResult pay(String orderNo, String amount, String openId, Integer payType) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount); //微信的分程序已做了转换，此次不用管
        if (StringUtils.isNotBlank(openId)) {
            payBean.setOpenId(openId);//"openid如果是公众号或小程序需要设置否则不用管"}
        }
        payBean.setPayType(payType);
        payBean.setIp(HttpClientUtil.localIp());

        ApiResult apiResult = null;
        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    /**
     * 支付
     *
     * @param
     * @return
     */
    @Override
    public ApiResult pay(String orderNo, String amount, String openId, Integer payType, String description) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount); //微信的分程序已做了转换，此次不用管
        if (StringUtils.isNotBlank(openId)) {
            payBean.setOpenId(openId);//"openid如果是公众号或小程序需要设置否则不用管"}
        }
        payBean.setPayType(payType);
        payBean.setIp(HttpClientUtil.localIp());
        payBean.setDescription(description);
        ApiResult apiResult = null;
        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    /**
     * 汇付
     *
     * @param
     * @return
     */
    @Override
    public ApiResult pay(String orderNo, String amount, String goodsTitle, String goodsDesc, Integer payType, String description) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount);
        payBean.setPayType(payType);
        payBean.setIp(HttpClientUtil.localIp());
        payBean.setDescription(description);
        payBean.setGoodsTitle(goodsTitle);
        payBean.setGoodsDesc(goodsDesc);
        ApiResult apiResult = null;
        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    @Override
    public ApiResult pay(String orderNo, String tokenNo, String amount, String goodsTitle, String goodsDesc, Integer payType, String description) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount);
        payBean.setPayType(payType);
        payBean.setIp(HttpClientUtil.localIp());
        payBean.setDescription(description);
        payBean.setGoodsTitle(goodsTitle);
        payBean.setGoodsDesc(goodsDesc);
        payBean.setTokenNo(tokenNo);
        ApiResult apiResult = null;
        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    /**
     * 快钱快捷支付专用方法
     */
    @Override
    public ApiResult pay(String orderNo, String amount, Integer payType, String description, String longitude, String latitude, String validCode) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount);
        payBean.setPayType(payType);
//        payBean.setIp(HttpClientUtil.localIp());
        payBean.setIp(IPUtils.getIpAddr(HttpContextUtils.getHttpServletRequest()));
        payBean.setDescription(description);
        payBean.setLongitude(longitude);
        payBean.setLatitude(latitude);
        ApiResult apiResult = null;
        // 快钱支付
        if (PayConstant.PayType.QUICK_PAY_BANK.getCode().equals(payType)) {
            // 快钱快捷支付逻辑
            // 快钱支付不进行订单验证,等待回调进行支付成功验证-调用快钱成功后,直接返回success,等待快钱回调逻辑验证订单成功

            // 获取快钱redis订单信息缓存
            KqPayInfoDTO kqPayInfoDTO = redisUtils.get(RedisKeys.getKqBankPay(orderNo), KqPayInfoDTO.class);

            // 保存验证码
            kqPayInfoDTO.setValidCode(validCode);

            // 该boolen标识业务标识,不能保证支付成功,需要通过回调确认支付结果
            KqPayMsgInfoDTO res = new KqPayMsgInfoDTO();

            if (KqPayTypeEnum.UNBIND.getCode().equals(kqPayInfoDTO.getKqPayType())) {
                // 首次绑卡业务
                res = firstBindingCardPay(kqPayInfoDTO);

            } else {
                // 快钱支付业务
                res = secondCertificationPay(kqPayInfoDTO);
            }

            if (res.isFlag()) {
                return ApiResult.success();
            } else {
                throw new RRException(res.getMsg());
            }
        }

        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    @Override
    public ApiResult pay(String orderNo, String amount, Integer payType, String description, String longitude, String latitude) {
        //生成支付信息给前台，供其唤起相应的支付
        PayBean payBean = new PayBean();
        payBean.setOrderNo(orderNo);
        payBean.setAmount(amount);
        payBean.setPayType(payType);
//        payBean.setIp(HttpClientUtil.localIp());
        payBean.setIp(IPUtils.getIpAddr(HttpContextUtils.getHttpServletRequest()));
        payBean.setDescription(description);
        payBean.setLongitude(longitude);
        payBean.setLatitude(latitude);
        ApiResult apiResult = null;
        // 快钱支付
        if (PayConstant.PayType.QUICK_PAY_AWE_CHAT.getCode().equals(payType)) {
            String res = InitOrder.gateWayInitOrder(new BigDecimal(amount), orderNo, QuickPayEnum.PayType.W2.getCode(), description);
            JSONObject object = JSON.parseObject(res);
            Integer resultCode = object.getInteger("resultCode");
            if(resultCode == 1) {
                return ApiResult.success(object.getJSONObject("mpayInfo"));
            } else {
                throw new RRException(object.getString("resultMessage"));
            }
        } else if (PayConstant.PayType.QUICK_PAY_ALIPAY.getCode().equals(payType)) {
            String res = InitOrder.gateWayInitOrder(new BigDecimal(amount), orderNo, QuickPayEnum.PayType.A2.getCode(), description);
            JSONObject object = JSON.parseObject(res);
            Integer resultCode = object.getInteger("resultCode");
            if(resultCode == 1) {
                return ApiResult.success(object.getJSONObject("mpayInfo"));
            } else {
                throw new RRException(object.getString("resultMessage"));
            }
        }

        try {
            apiResult = payService.createPayOrder(payBean);
            return apiResult;
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }


    @Override
    public PayOrder getByUserIdAndId(Long userId, Long payOrderId, Boolean tw) {
        PayOrder payOrder = this.getOne(new LambdaQueryWrapper<PayOrder>()
                .eq(PayOrder::getUserId, userId)
                .eq(PayOrder::getId, payOrderId)
                .last("limit 1"));
        if (payOrder == null) {
            if (tw) {
                throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
            }
        }
        return payOrder;
    }

    @Override
    public List<PayOrder> getExpiredOrder(long timeMillis) {
        List<PayOrder> list = this.list(
                new LambdaQueryWrapper<PayOrder>()
                        .eq(PayOrder::getPaymentStatus, OrderConstant.PaymentStatus.NO_PAY)//未支付
                        .eq(PayOrder::getCloseMode, OrderConstant.CloseMode.NO)//未关闭
                        .eq(PayOrder::getClose, false)//未关闭
                        .le(PayOrder::getExpiredPayTime, timeMillis)//expored_pay_time<=timeMillis
        );

        return list;
    }

    /**
     * 普通支付订单查询
     *
     * @param userId
     * @param payOrderId
     * @return
     */
    @Override
    public PayOrderDetailVo getPayOrderSakeDetail(Long userId, Long payOrderId) {

        PayOrder payOrder = this.getByUserIdAndId(userId, payOrderId, true);
        PayOrderDetailVo vo = new PayOrderDetailVo();
        vo.setPayOrder(payOrder);
        List<Order> orders = orderService.loadByPayOrderId(payOrderId);
        Order order = orders.get(0);
        vo.setShipmentMode(order.getShipmentMode());
        if (OrderConstant.ShipmentMode.EXPRESS.equals(order.getShipmentMode())) {
            vo.setReceipt(order.loadOrderReceipt());
        } else {
            vo.setSelfTake(order.loadOrderSelfTake());
            vo.setSelfTakeShop(order.loadShop());
        }

        orders.forEach(o -> {
            o.getChildOrderList(true);
            o.loadShop();
        });
        vo.setOrderList(orders);

        return vo;
    }

    @Override
    public void verifyCloseOrder(PayOrder payOrder) {
        if (payOrder == null) {
            throw new RRException(OrderException.PAY_ORDER_NOT_EXISTS);
        }

        if (payOrder.getClose()) {
            //支付订单已关闭,不能取消支付
            throw new RRException(OrderException.PAY_ORDER_CLOSED);
        }

        if (payOrder.isFactPaySuccess()) {
            //支付订单已成功支付,不取消支付
            throw new RRException(OrderException.PAY_SUCCESS_NOT_CLOSE);
        }
    }

    @Override
    public Integer waitPayNum(Long userId, OrderConstant.OrderType type, Integer areaFeature) {
        Integer[] areaFeatures = new Integer[]{0, 1, 2};
        Integer count = this.count(new LambdaQueryWrapper<PayOrder>()
                .eq(PayOrder::getUserId, userId)
                .eq(PayOrder::getOrderType, type.getCode())
                .eq(PayOrder::getPaymentStatus, OrderConstant.PaymentStatus.NO_PAY)
                .in(areaFeature != null && areaFeature == 0, PayOrder::getAreaFeature, Arrays.asList(areaFeatures))
                .eq(areaFeature != null && areaFeature > 0, PayOrder::getAreaFeature, areaFeature)
                .eq(PayOrder::getClose, false));
        return count;
    }

    @Override
    public Map<String, Object> kjPayConfirm(AdaPayKJPayConfirmDTO dto) {
        AdaPayConfirmBean adaPayConfirmBean = new AdaPayConfirmBean();
        adaPayConfirmBean.setPaymentId(dto.getPaymentId());
        adaPayConfirmBean.setSmsCode(dto.getSmsCode());

        try {
            return adaKjPayService.paySendSms(adaPayConfirmBean,(o)->{
                //不要起用走回调
//                Map<String, Object> result = (Map<String, Object>)o;
//                String outTradeNo = result.get("order_no").toString();
//                String money = result.get("pay_amt").toString();
//                String transactionId = result.get("id").toString();
//                //处理支付逻辑
//                PayOrder payOrder = this.paymentHandle(outTradeNo, transactionId, new BigDecimal(money), OrderConstant.PayMode.KJ);
//                //消费订单  支付成功发送消息
//                if (!payOrder.getOrderType().equals(OrderConstant.OrderType.REFILL_ORDER)) {
//                    sendOrderOrRightsOrderMsgService.paySuccessSendMsg(payOrder);
//                } else {
//                    //发送充值商品支付成功站内消息
//                    sendPrivateMessageMsgService.send(new MessageTO(PrivateMessageConstant.MessageType.PAY_MESSAGE,
//                            PrivateMessageConstant.ModelType.REFILL_PAY_SUCCESS, payOrder.getId()));
//                }
                return null;
            });
        } catch (Exception ex) {
            throw new RRException(ex.getMessage());
        }


    }

    @Override
    public Map<String, Object> payRepeatSendSms(AdaPayKJPayConfirmDTO dto) {
        AdaPayConfirmBean adaPayConfirmBean = new AdaPayConfirmBean();
        adaPayConfirmBean.setPaymentId(dto.getPaymentId());
        adaPayConfirmBean.setSmsCode(dto.getSmsCode());

        try {
            return adaKjPayService.payRepeatSendSms(adaPayConfirmBean);
        } catch (Exception ex) {
            throw new RRException(ex.getMessage());
        }


    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Long userId = MapUtil.getLong(params, "user_id");
        Integer paymentStatus = MapUtil.getInt(params, "payment_status");
        Integer orderType = MapUtil.getInt(params, "order_type");
        String code = MapUtil.getStr(params, "code");
        String thirdPayCode = MapUtil.getStr(params, "third_pay_code");
        String client = MapUtil.getStr(params, "client");
        Integer areaFeature = MapUtil.getInt(params, "area_feature");
        Integer[] areaFeatures = new Integer[]{0, 1, 2};
        Boolean close = null;
        if (StringUtils.isNotBlank(MapUtil.getStr(params, "close"))) {
            close = MapUtil.getBool(params, "close");
        }


        IPage<PayOrder> page = this.page(
                new Query<PayOrder>().getPage(params),
                new LambdaQueryWrapper<PayOrder>()
                        .eq(userId != null, PayOrder::getUserId, userId)
                        .eq(paymentStatus != null, PayOrder::getPaymentStatus, paymentStatus)
                        .eq(orderType != null, PayOrder::getOrderType, orderType)
                        .eq(close != null, PayOrder::getClose, close)
                        .in(areaFeature != null && areaFeature == 0, PayOrder::getAreaFeature, Arrays.asList(areaFeatures))
                        .eq(areaFeature != null && areaFeature > 0, PayOrder::getAreaFeature, areaFeature)

                        .like(StringUtils.isNotBlank(code), PayOrder::getCode, code)
                        .like(StringUtils.isNotBlank(thirdPayCode), PayOrder::getThirdPayCode, thirdPayCode)
                        //.eq(StringUtils.isNotBlank(client) && client.equals("applet"), PayOrder::getPointGoods, false)
                        .orderByDesc(PayOrder::getCreateTimeMillis)
        );

        //加载商品数量
        page.getRecords().forEach(o -> {
            o.loadGoodsNumber();
            List<Order> orders = o.loadOrders();
            orders.forEach(order -> {
                order.loadShop();
                order.getChildOrderList(true);
            });
        });

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageAll(Map<String, Object> params) {
        Long userId = MapUtil.getLong(params, "user_id");
        Integer orderType = MapUtil.getInt(params, "order_type");
        String code = MapUtil.getStr(params, "code");
        String thirdPayCode = MapUtil.getStr(params, "third_pay_code");
        String client = MapUtil.getStr(params, "client");
        Integer areaFeature = MapUtil.getInt(params, "area_feature");
        Integer[] areaFeatures = new Integer[]{0, 1, 2};
        IPage<PayOrder> page = this.page(
                new Query<PayOrder>().getPage(params),
                new LambdaQueryWrapper<PayOrder>()
                        .eq(userId != null, PayOrder::getUserId, userId)
                        .eq(orderType != null, PayOrder::getOrderType, orderType)
                        .in(areaFeature != null && areaFeature == 0, PayOrder::getAreaFeature, Arrays.asList(areaFeatures))
                        .eq(areaFeature != null && areaFeature > 0, PayOrder::getAreaFeature, areaFeature)
                        .like(StringUtils.isNotBlank(code), PayOrder::getCode, code)
                        .like(StringUtils.isNotBlank(thirdPayCode), PayOrder::getThirdPayCode, thirdPayCode)
                        .eq(PayOrder::getAdminOrder,false)
                        //.eq(StringUtils.isNotBlank(client) && client.equals("applet"), PayOrder::getPointGoods, false)
                        .orderByDesc(PayOrder::getCreateTimeMillis)
        );

        page.getRecords().forEach(payOrder -> {
//            if (OrderConstant.PaymentStatus.SUCCESS.equals(payOrder.getPaymentStatus())) {
//                List<Order> orders = payOrder.loadOrders();
//                orders.forEach(order -> {
//                    order.getChildOrderList(false);
//                    order.loadShop();
//                });
//            }
            List<Order> orders = payOrder.loadOrders();
            orders.forEach(order -> {
                order.getChildOrderList(false);
                order.loadShop();
            });
            //加载商品数量
            payOrder.loadGoodsNumber();
        });

        return new PageUtils(page);
    }

    /**
     * 银行卡信息查询
     * @param req
     * @return
     * @throws Exception
     */
    @Override
    public R getCardInfo(JSONObject req) throws Exception {

        JSONObject A9004Req = new JSONObject();
        JSONObject A9004ReqHead = new JSONObject();
        JSONObject A9004ReqBody = new JSONObject();

        A9004ReqHead.put("version", "1.0.0");
        A9004ReqHead.put("messageType", "A9004");
        A9004ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);

        A9004ReqBody.put("pan", req.getString("pan"));

        A9004Req.put("head", A9004ReqHead);
        A9004Req.put("requestBody", A9004ReqBody);
        String A9004ResStr = buildHttpsClient.requestKQ(A9004Req);

        if (StringUtils.isNotBlank(A9004ResStr)) {
            JSONObject A9004Res = JSONObject.parseObject(A9004ResStr);
            JSONObject A9004ResBody = A9004Res.getJSONObject("responseBody");

            // 快钱调用产生业务异常
            if (!"0000".equals(A9004ResBody.getString("bizResponseCode"))) {
                log.info("快钱银行卡查询:{}, 卡号:{}", A9004ResBody.getString("bizResponseMessage"), req.getString("pan"));
                return R.error(A9004ResBody.getString("bizResponseMessage"));
            }

            KqBankCardQueryDTO resDTO = A9004Res.getObject("responseBody", KqBankCardQueryDTO.class);
            return R.ok().put("data", resDTO);
        }
        return R.error();
    }

    /**
     * 本地快钱银行卡信息查询方法
     * @param pan
     * @return
     */
    public KqBankCardQueryDTO localGetCardInfo(String pan) throws Exception {
        JSONObject A9004Req = new JSONObject();
        JSONObject A9004ReqHead = new JSONObject();
        JSONObject A9004ReqBody = new JSONObject();

        A9004ReqHead.put("version", "1.0.0");
        A9004ReqHead.put("messageType", "A9004");
        A9004ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);

        A9004ReqBody.put("pan", pan);

        A9004Req.put("head", A9004ReqHead);
        A9004Req.put("requestBody", A9004ReqBody);

        String A9004ResStr = buildHttpsClient.requestKQ(A9004Req);

        if (StringUtils.isNotBlank(A9004ResStr)) {
            JSONObject A9004Res = JSONObject.parseObject(A9004ResStr);
            JSONObject A9004ResBody = A9004Res.getJSONObject("responseBody");

            // 快钱调用产生业务异常
            if (!"0000".equals(A9004ResBody.getString("bizResponseCode"))) {
                log.info("快钱银行卡查询:{}, 卡号:{}", A9004ResBody.getString("bizResponseMessage"), pan);
                return null;
            }
            KqBankCardQueryDTO resDTO = A9004Res.getObject("responseBody", KqBankCardQueryDTO.class);
            return resDTO;
        }
        return null;
    }

    /**
     * 用户绑定银行卡信息查询
     */
    @Override
    public R getUserBankInfo(KqUserBankInfoReqDTO req) {
        // 查询所有已激活的银行卡
        QueryWrapper<KqBank> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", req.getUserId());
        queryWrapper.eq("is_used", KqBankIsUsedEnum.USED.getCode());

        List<KqBank> list = kqBankDao.selectList(queryWrapper);
        return R.ok().put("data", list);
    }

    /**
     * 首次绑定银行卡+发送验证码,这一部分无需前端验证,返回200后唤起验证码页面即可
     */
    @Override
    public R firstBindingCard(KqFirstCertificationReqDTO req) throws Exception {

        // 前置校验-这里取消校验
        String redisKey = redisUtils.get(RedisKeys.getKqBankBindCode(req.getOrderNo()));
        if (StringUtils.isNotBlank(redisKey)) {
            return R.error("该银行卡:" + req.getPan() + "正在绑定中,请勿重复绑定,若绑定失败请于一分钟后重新绑定");
        }

        // 校验银行卡信息本地是否存在
        QueryWrapper<KqBank> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pan", req.getPan());
        KqBank kqBank = kqBankDao.selectOne(queryWrapper);

        if (!Objects.isNull(kqBank) && KqBankIsUsedEnum.USED.getCode().equals(kqBank.getPan())) {
            // 银行卡本地存在,且已激活时,阻拦该业务
            return R.error("该银行卡:" + req.getPan() + "已被激活");
        }

        // 本地存在且未激活,与本地不存在时,进行激活业务
        // 调用快钱银行卡数据查询
        KqBankCardQueryDTO kqBankCardQueryDTO = new KqBankCardQueryDTO();
        try {
            kqBankCardQueryDTO = localGetCardInfo(req.getPan());

            if (!KqValidFlagEnum.OK.getCode().equals(kqBankCardQueryDTO.getValidFlag())) {
                // 校验该银行卡是否满足快钱策略
                log.info("该银行卡不满足快钱策略,拒绝绑定,卡号:{}", req.getPan());
                return R.error("该银行卡不满足快钱策略");
            }
        } catch (Exception e) {
            log.info("调用快钱银行卡查询失败,卡号:{}", req.getPan());
            return R.error("银行卡识别失败");
        }

        if (Objects.isNull(kqBank)) {
            // 本地不存在时,保留数据库
            kqBank = new KqBank();

            kqBank.setUserId(req.getUserId());
            kqBank.setUserName(req.getUserName());

            kqBank.setCertNo(req.getCertNo());
            kqBank.setRealName(req.getRealName());

            kqBank.setPan(req.getPan());
            // 这里注意,所有银行卡初始化的时候,均属于未激活,在完成支付(回调)时,进行激活
            kqBank.setIsUsed(KqBankIsUsedEnum.UNUSED.getCode());
            kqBank.setCreateTime(new Date());

            kqBank.setIssuer(kqBankCardQueryDTO.getIssuer());
            kqBank.setBankId(kqBankCardQueryDTO.getBankId());
            kqBank.setCardOrg(kqBankCardQueryDTO.getCardOrg());
            kqBank.setCardType(kqBankCardQueryDTO.getCardType());
            kqBank.setPhone(req.getPhone());

            // 信用卡逻辑
            if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqBankCardQueryDTO.getCardType())) {
                kqBank.setCvv2(req.getCvv2());
                kqBank.setExpiredDate(req.getExpiredDate());
            }

            kqBankDao.insert(kqBank);
        }

        // 调用快钱消费签约申请
        JSONObject A2001Req = new JSONObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        JSONObject A2001ReqHead = new JSONObject();
        A2001ReqHead.put("version", "1.0.0");
        A2001ReqHead.put("messageType", "A2001");
        A2001ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);
        A2001ReqHead.put("externalRefNumber",  req.getOrderNo());

        JSONObject A2001ReqBody = new JSONObject();
        A2001ReqBody.put("merchantId", Bill99ConfigInfo.MERCHANT_ID);
        A2001ReqBody.put("customerId", req.getUserId());
        A2001ReqBody.put("pan", req.getPan());
        A2001ReqBody.put("cardHolderName", req.getRealName());
        // 证件类型,默认0身份证
        A2001ReqBody.put("idType", "0");
        A2001ReqBody.put("cardHolderId", req.getCertNo());
        A2001ReqBody.put("bankId", kqBankCardQueryDTO.getBankId());
        A2001ReqBody.put("phoneNo", req.getPhone());
        A2001ReqBody.put("amount", req.getAmount());
        A2001ReqBody.put("protocolVersion", Bill99ConfigInfo.PROTOCOL_VERSION);
        A2001ReqBody.put("protocolNo", Bill99ConfigInfo.PROTOCOL_NO);

        // 信用卡业务
        if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqBank.getCardType())) {
            A2001ReqBody.put("expiredDate", req.getExpiredDate());
            A2001ReqBody.put("cvv2", req.getCvv2());
        }

        A2001Req.put("head", A2001ReqHead);
        A2001Req.put("requestBody", A2001ReqBody);

        String A2001ResStr = buildHttpsClient.requestKQ(A2001Req);
        JSONObject A2001Res = JSONObject.parseObject(A2001ResStr);

        JSONObject A2001ResBody = A2001Res.getJSONObject("responseBody");

        // 快钱调用产生业务异常
        if (!"0000".equals(A2001ResBody.getString("bizResponseCode"))) {
            log.info("快钱银行卡绑定:{}, 卡号:{}", A2001ResBody.getString("bizResponseMessage"), req.getPan());
            return R.error(A2001ResBody.getString("bizResponseMessage"));
        }

        // 获取返回值更新token--这里的token不是支付paytoken,签约短信验证时需要与验证码一起上传的token
        kqBank.setToken(A2001ResBody.getString("token"));

        if ((A2001ResBody.containsKey("payToken"))) {
            kqBank.setPayToken(A2001ResBody.getString("payToken"));
        } else {
            log.info("快钱未返回paytoken,可能该用户该卡重复绑定");
        }

        kqBankDao.updateById(kqBank);

        //保存外部跟踪编号,等待验证码验证
        redisUtils.set(RedisKeys.getKqBankBindCode(req.getOrderNo()), req.getOrderNo(), 60);

        // 这里增加快钱-惠选业务类型--未绑定银行卡支付
        // 缓存该订单该人员银行卡信息
        KqPayInfoDTO kqPayInfoDTO = new KqPayInfoDTO();
        kqPayInfoDTO.setKqPayType(KqPayTypeEnum.UNBIND.getCode());
        kqPayInfoDTO.setPan(req.getPan());
        kqPayInfoDTO.setPhone(req.getPhone());
        kqPayInfoDTO.setPayToken(kqBank.getPayToken());

        kqPayInfoDTO.setCertNo(req.getCertNo());
        kqPayInfoDTO.setRealName(req.getRealName());
        kqPayInfoDTO.setUserId(req.getUserId());
        kqPayInfoDTO.setOrderNo(req.getOrderNo());
        kqPayInfoDTO.setAmount(req.getAmount());
        // token为快钱业务验证token,从前置业务获取后,保存至redis
        kqPayInfoDTO.setToken(A2001ResBody.getString("token"));

        kqPayInfoDTO.setCardType(kqBank.getCardType());
        if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqBank.getCardType())) {
            // 信用卡增加参数
            kqPayInfoDTO.setExpiredDate(req.getExpiredDate());
            kqPayInfoDTO.setCvv2(req.getCvv2());
        }

        redisUtils.set(RedisKeys.getKqBankPay(req.getOrderNo()), kqPayInfoDTO, 600);

        KqFirstCertificationResDTO resDTO = new KqFirstCertificationResDTO();
        resDTO.setUserId((A2001Res.getJSONObject("responseBody").getString("customerId")));

        return R.ok().put("data", resDTO);
    }

    /**
     * 首次绑卡-签约扣款认证
     */
    public KqPayMsgInfoDTO firstBindingCardPay(KqPayInfoDTO kqPayInfoDTO) {
        JSONObject A2002Req = new JSONObject();
        JSONObject A2002ReqHead = new JSONObject();
        JSONObject A2002ReqBody = new JSONObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

        A2002ReqHead.put("version", "1.0.0");
        A2002ReqHead.put("messageType", "A2002");
        A2002ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);
        // 这里的externalRefNumber应与前置流程A2001中保持一致
        A2002ReqHead.put("externalRefNumber", kqPayInfoDTO.getOrderNo());

        A2002ReqBody.put("merchantId", Bill99ConfigInfo.MERCHANT_ID);
        A2002ReqBody.put("terminalId", Bill99ConfigInfo.TERMINAL_ID);
        A2002ReqBody.put("entryTime", sdf.format(new Date()));
        A2002ReqBody.put("customerId", kqPayInfoDTO.getUserId());
        A2002ReqBody.put("pan", kqPayInfoDTO.getPan());
        A2002ReqBody.put("cardHolderName", kqPayInfoDTO.getRealName());
        A2002ReqBody.put("cardHolderId", kqPayInfoDTO.getCertNo());
        A2002ReqBody.put("phoneNo", kqPayInfoDTO.getPhone());
        A2002ReqBody.put("amount", kqPayInfoDTO.getAmount());
        A2002ReqBody.put("validCode", kqPayInfoDTO.getValidCode());
        A2002ReqBody.put("token", kqPayInfoDTO.getToken());
        // 异步通知地址
        A2002ReqBody.put("tr3Url", Bill99ConfigInfo.NOTIFY_URL);

        // 信用卡业务
        if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqPayInfoDTO.getCardType())) {
            A2002ReqBody.put("expiredDate", kqPayInfoDTO.getExpiredDate());
            A2002ReqBody.put("cvv2", kqPayInfoDTO.getCvv2());
        }

        A2002Req.put("head", A2002ReqHead);
        A2002Req.put("requestBody", A2002ReqBody);

        JSONObject A2002Res = new JSONObject();
        JSONObject A2002ResBody = new JSONObject();
        JSONObject A2002ResHead = new JSONObject();

        KqPayMsgInfoDTO res = new KqPayMsgInfoDTO();
        res.setFlag(false);

        try {
            String A2002ResStr = buildHttpsClient.requestKQ(A2002Req);
            A2002Res = JSONObject.parseObject(A2002ResStr);

            A2002ResBody = A2002Res.getJSONObject("responseBody");
            A2002ResHead = A2002Res.getJSONObject("head");
            // 快钱调用产生业务异常

//            if (!"0000".equals(A2002ResHead.getString("responseCode"))) {
//                log.info("快钱银行卡签约扣款认证:{}, 卡号:{}", A2002ResHead.getString("responseTextMessage"), kqPayInfoDTO.getPan());
//                return false;
//            }

            if (!"0000".equals(A2002ResBody.getString("bizResponseCode"))) {
                log.info("快钱银行卡签约扣款认证:{}, 卡号:{}", A2002ResBody.getString("bizResponseMessage"), kqPayInfoDTO.getPan());
                res.setMsg(A2002ResBody.getString("bizResponseMessage"));
                return res;
            }

            // 首次付款成功,回写kq_bank数据库银行卡状态
            QueryWrapper<KqBank> kqBankQueryWrapper = new QueryWrapper<>();
            kqBankQueryWrapper.eq("pan", kqPayInfoDTO.getPan());
            KqBank kqBank = kqBankDao.selectOne(kqBankQueryWrapper);
            kqBank.setIsUsed(KqBankIsUsedEnum.USED.getCode());
            kqBankDao.updateById(kqBank);

        } catch (Exception e) {
            log.info("快钱银行卡签约扣款认证:{}, 卡号:{}", A2002ResBody.getString("bizResponseMessage"), kqPayInfoDTO.getPan());
            log.info("快钱银行卡签约扣款认证异常卡号:{}", kqPayInfoDTO.getPan());
            res.setMsg(A2002ResBody.getString("bizResponseMessage"));
            return res;
        }
        res.setFlag(true);
        return res;
    }

    /**
     * 快捷支付
     */
    public KqPayMsgInfoDTO secondCertificationPay(KqPayInfoDTO kqPayInfoDTO) {
        JSONObject A2004Req = new JSONObject();
        JSONObject A2004ReqHead = new JSONObject();
        JSONObject A2004ReqBody = new JSONObject();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

        A2004ReqHead.put("version", "1.0.0");
        A2004ReqHead.put("messageType", "A2004");
        A2004ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);
        // 这里的externalRefNumber应与前置流程A2003中保持一致
        A2004ReqHead.put("externalRefNumber", kqPayInfoDTO.getOrderNo());

        A2004ReqBody.put("merchantId", Bill99ConfigInfo.MERCHANT_ID);
        A2004ReqBody.put("terminalId", Bill99ConfigInfo.TERMINAL_ID);

        A2004ReqBody.put("entryTime", sdf.format(new Date()));
        A2004ReqBody.put("customerId", kqPayInfoDTO.getUserId());
        A2004ReqBody.put("pan", kqPayInfoDTO.getPan());

        A2004ReqBody.put("phoneNo", kqPayInfoDTO.getPhone());
        A2004ReqBody.put("amount", kqPayInfoDTO.getAmount());
        A2004ReqBody.put("validCode", kqPayInfoDTO.getValidCode());
        A2004ReqBody.put("token", kqPayInfoDTO.getToken());
        // 异步通知地址
        A2004ReqBody.put("tr3Url", Bill99ConfigInfo.NOTIFY_URL);

        // 信用卡业务
        if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqPayInfoDTO.getCardType())) {
            A2004ReqBody.put("expiredDate", kqPayInfoDTO.getExpiredDate());
            A2004ReqBody.put("cvv2", kqPayInfoDTO.getCvv2());
        }

        // 银行卡缩略号与payToken二选一,这里为保证业务逻辑正常运行,进行双向判断
        if (StringUtils.isEmpty(kqPayInfoDTO.getPayToken())) {
            A2004ReqBody.put("storablePan", getBankCardStorablePan(kqPayInfoDTO.getPan()));

        } else {
            A2004ReqBody.put("payToken", kqPayInfoDTO.getPayToken());
        }
        KqPayMsgInfoDTO res = new KqPayMsgInfoDTO();
        res.setFlag(false);

        A2004Req.put("head", A2004ReqHead);
        A2004Req.put("requestBody", A2004ReqBody);

        JSONObject A2004Res = new JSONObject();
        JSONObject A2004ResBody = new JSONObject();
        try {
            String A2002ResStr = buildHttpsClient.requestKQ(A2004Req);
            A2004Res = JSONObject.parseObject(A2002ResStr);

            A2004ResBody = A2004Res.getJSONObject("responseBody");

            // 快钱调用产生业务异常
            if (!"0000".equals(A2004ResBody.getString("bizResponseCode"))) {
                log.info("快钱银行卡支付:{}, 卡号:{}", A2004ResBody.getString("bizResponseMessage"), kqPayInfoDTO.getPan());
                res.setMsg(A2004ResBody.getString("bizResponseMessage"));
                return res;
            }

        } catch (Exception e) {
            log.info("快钱银行卡签约扣款认证:{}, 卡号:{}", A2004ResBody.getString("bizResponseMessage"), kqPayInfoDTO.getPan());
            log.info("快钱银行卡签约扣款认证异常卡号:{}", kqPayInfoDTO.getPan());
            res.setMsg(A2004ResBody.getString("bizResponseMessage"));
            return res;
        }
        res.setFlag(true);
        return res;
    }

    /**
     * 内部方法-银行卡缩略号前6后4位获取
     */
    public String getBankCardStorablePan(String pan) {
        String first6 = pan.substring(0, 6);
        String last4 = pan.substring(pan.length() - 4);
        return first6 + last4;
    }

    /**
     * 已绑卡-快捷支付申请
     */
    @Override
    public R kqPayApply(KqPayApplyReqDTO req) throws Exception {

        // 前置校验
        String redisKey = redisUtils.get(RedisKeys.getKqBankPayCode(req.getOrderNo()));
        if (StringUtils.isNotBlank(redisKey)) {
            return R.error("该银行卡:" + req.getPan() + "正在支付中,请勿重新发起");
        }

        // 验证入参
        QueryWrapper<KqBank> kqBankQueryWrapper = new QueryWrapper<>();
        kqBankQueryWrapper.eq("pan", req.getPan());
        kqBankQueryWrapper.eq("user_id", req.getUserId());

        KqBank kqBank = kqBankDao.selectOne(kqBankQueryWrapper);
        if (Objects.isNull(kqBank)) {
            // 银行卡本地不存在
            return R.error("该银行卡:" + req.getPan() + "未绑定");
        }

        if (!Objects.isNull(kqBank) && KqBankIsUsedEnum.UNUSED.getCode().equals(kqBank.getPan())) {
            // 银行卡本地存在,且未激活时,阻拦该业务
            return R.error("该银行卡:" + req.getPan() + "未激活");
        }

        JSONObject A2003Req = new JSONObject();
        JSONObject A2003ReqBody = new JSONObject();
        JSONObject A2003ReqHead = new JSONObject();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        A2003ReqHead.put("version", "1.0.0");
        A2003ReqHead.put("messageType", "A2003");
        A2003ReqHead.put("memberCode", Bill99ConfigInfo.MEMBER_CODE);
        // 这里绑定订单号
        A2003ReqHead.put("externalRefNumber", req.getOrderNo());

        A2003ReqBody.put("merchantId", Bill99ConfigInfo.MERCHANT_ID);
        A2003ReqBody.put("customerId", req.getUserId());

        // 银行卡缩略号与payToken二选一,这里为保证业务逻辑正常运行,进行双向判断
        if (StringUtils.isEmpty(kqBank.getPayToken())) {
        A2003ReqBody.put("storablePan", getBankCardStorablePan(req.getPan()));

        } else {
            A2003ReqBody.put("payToken", kqBank.getPayToken());
        }

        A2003ReqBody.put("amount", req.getAmount());

        A2003Req.put("head", A2003ReqHead);
        A2003Req.put("requestBody", A2003ReqBody);

        String A2003ResStr = buildHttpsClient.requestKQ(A2003Req);
        JSONObject A2003Res = JSONObject.parseObject(A2003ResStr);

        JSONObject A2003ResBody = A2003Res.getJSONObject("responseBody");
        JSONObject A2003ResHead = A2003Res.getJSONObject("head");
        // 快钱调用产生业务异常
        if (!"0000".equals(A2003ResHead.get("responseCode"))) {
            log.info("快钱银行卡支付申请:{}, 卡号:{}", A2003ResBody.getString("responseTextMessage"), req.getPan());

            return R.error("支付调用异常");

        }

        if (!"0000".equals(A2003ResBody.getString("bizResponseCode"))) {
            log.info("快钱银行卡支付申请:{}, 卡号:{}", A2003ResBody.getString("bizResponseMessage"), req.getPan());
            return R.error(A2003ResBody.getString("bizResponseMessage"));
        }
        //保存外部跟踪编号,等待验证码验证
        redisUtils.set(RedisKeys.getKqBankPayCode(req.getOrderNo()), req.getOrderNo(), 60);

        // 这里增加快钱-惠选业务类型--已绑定银行卡支付
        KqPayInfoDTO kqPayInfoDTO = new KqPayInfoDTO();
        kqPayInfoDTO.setKqPayType(KqPayTypeEnum.BIND.getCode());
        kqPayInfoDTO.setPan(req.getPan());
        kqPayInfoDTO.setPhone(kqBank.getPhone());
        kqPayInfoDTO.setPayToken(kqBank.getPayToken());

        kqPayInfoDTO.setCertNo(kqBank.getCertNo());
        kqPayInfoDTO.setRealName(kqBank.getRealName());
        kqPayInfoDTO.setUserId(req.getUserId());
        kqPayInfoDTO.setOrderNo(req.getOrderNo());
        kqPayInfoDTO.setAmount(req.getAmount());
        // token为快钱业务验证token,从前置业务获取后,保存至redis
        kqPayInfoDTO.setToken(A2003ResBody.getString("token"));

        kqPayInfoDTO.setCardType(kqBank.getCardType());
        if (KqBankCardTyepEnum.CREDIT.getCode().equals(kqBank.getCardType())) {
            // 信用卡增加参数
            kqPayInfoDTO.setExpiredDate(kqBank.getExpiredDate());
            kqPayInfoDTO.setCvv2(kqBank.getCvv2());
        }

        redisUtils.set(RedisKeys.getKqBankPay(req.getOrderNo()), kqPayInfoDTO, 600);

        KqPayApplyResDTO resDTO = new KqPayApplyResDTO();
        resDTO.setUserId(req.getUserId());

        return R.ok().put("data", resDTO);
    }

    /**
     * 用户关闭验证码弹窗策略-这里为保证,用户每次唤起验证码激活时,redis中的externalRefNumber始终保证业务一致性-暂时不用
     */
    @Override
    public R closeVerify(KqCloseVerifyReqDTO req) {
        if (req.isFirst()) {
            // 首次绑定业务
            String redisKey = redisUtils.get(RedisKeys.getKqBankBindCode(req.getPan() + '_' + req.getOrderNo()));
            if (StringUtils.isNotBlank(redisKey)) {
                // 不是空时,清除redis缓存信息
                redisUtils.delete(RedisKeys.getKqBankBindCode(req.getPan() + '_' + req.getOrderNo()));
            }
        } else {
            // 支付业务
            String redisKey = redisUtils.get(RedisKeys.getKqBankPayCode(req.getPan() + '_' + req.getOrderNo()));
            if (StringUtils.isNotBlank(redisKey)) {
                // 不是空时,清除redis缓存信息
                redisUtils.delete(RedisKeys.getKqBankPayCode(req.getPan() + '_' + req.getOrderNo()));
            }
        }
        return R.ok();
    }



}
